package top.meeting.room.common.kit;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.Kv;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.meeting.room.common.config.MainConfig;
import top.meeting.room.module.system.form.PushMsgForm;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * Created by Lyt on 2017/9/13.
 */
public class WxKit {
    private static final Logger _log = LoggerFactory.getLogger(WxKit.class);

    private static final String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
    private static final String authorize_uri = "https://open.weixin.qq.com/connect/oauth2/authorize";
    private static final String userinfo_url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
    private static final String sendmsg_url = "https://qyapi.weixin.qq.com/cgi-bin/message/send";
    private static final String userdetail_url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail";
    private static final String CHARSET = "UTF-8";

    /**
     * 组装签名的字段
     *
     * @param params     参数
     * @param urlEncoder 是否urlEncoder
     * @return String
     */
    public static String packageSign(Map<String, String> params, boolean urlEncoder) {
        // 先将参数以其参数名的字典序升序进行排序
        TreeMap<String, String> sortedParams = new TreeMap<String, String>(params);
        // 遍历排序后的字典，将所有参数按"key=value"格式拼接在一起
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> param : sortedParams.entrySet()) {
            String value = param.getValue();
            if (StrKit.isBlank(value)) {
                continue;
            }
            if (first) {
                first = false;
            } else {
                sb.append("&");
            }
            sb.append(param.getKey()).append("=");
            if (urlEncoder) {
                try {
                    value = urlEncode(value);
                } catch (UnsupportedEncodingException e) {
                }
            }
            sb.append(value);
        }
        return sb.toString();
    }

    /**
     * urlEncode
     *
     * @param src 微信参数
     * @return String
     * @throws UnsupportedEncodingException
     */
    public static String urlEncode(String src) throws UnsupportedEncodingException {
        return URLEncoder.encode(src, CHARSET).replace("+", "%20");
    }

    /**
     * 生成Authorize链接
     *
     * @param appId        应用id
     * @param redirect_uri 回跳地址
     * @param state        重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
     * @param snsapiBase   snsapi_base（不弹出授权页面，只能拿到用户openid）snsapi_userinfo（弹出授权页面，这个可以通过 openid 拿到昵称、性别、所在地）
     * @return url
     */
    public static String getAuthorizeURL(String appId, String redirect_uri, boolean snsapiBase, String state) {

        Map<String, String> params = new HashMap<String, String>();
        params.put("appid", appId);
        params.put("redirect_uri", redirect_uri);
        params.put("response_type", "code");
        // snsapi_base（不弹出授权页面，只能拿到用户openid）
        // snsapi_userinfo（弹出授权页面，这个可以通过 openid 拿到昵称、性别、所在地）
        if (snsapiBase) {
            params.put("scope", "snsapi_base");
        } else {
            params.put("scope", "snsapi_userinfo");
        }
        if (StrKit.isBlank(state)) {
            params.put("state", "wx#wechat_redirect");
        } else {
            params.put("state", state.concat("#wechat_redirect"));
        }

        String para = packageSign(params, false);
        return authorize_uri + "?" + para;
    }

    public static JSONObject getAccessToken(String corpId, String secret) {
        JSONObject result = HttpKit.doGetJson(String.format("%s?corpid=%s&corpsecret=%s", access_token_url, corpId, secret));

        Object errCode = result == null ? null : result.get("errcode");
        if (null != errCode && Integer.valueOf(errCode.toString()) > 0) {
            _log.error("Fail to get Sns Access Token: {}, {}", errCode, result.get("errmsg"));
            return null;
        }

        return result;
    }

    public static JSONObject getUserInfo(String accessToken, String code) {
        JSONObject result = HttpKit.doGetJson(String.format("%s?access_token=%s&code=%s", userinfo_url, accessToken, code));
        Object errCode = result == null ? null : result.get("errcode");
        if (null != errCode && Integer.valueOf(errCode.toString()) > 0) {
            _log.error("Fail to get user info: {}, {}", errCode, result.get("errmsg"));
            return null;
        }
        return result;
    }

    public static JSONObject getUserDetail(String accessToken, String user_ticket) {
        String resultStr = com.jfinal.kit.HttpKit.post(userdetail_url + "?access_token=" + accessToken, null, JsonKit.toJson(Kv.by("user_ticket", user_ticket)));
        JSONObject result = JSONObject.parseObject(resultStr);
        return (result != null && StrKit.notBlank(result.getString("department"), result.getString("name"))) ? result : null;
    }


    private static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {
        if (queryParas == null || queryParas.isEmpty())
            return url;

        StringBuilder sb = new StringBuilder(url);
        boolean isFirst;
        if (url.indexOf("?") == -1) {
            isFirst = true;
            sb.append("?");
        } else {
            isFirst = false;
        }

        for (Map.Entry<String, String> entry : queryParas.entrySet()) {
            if (isFirst) isFirst = false;
            else sb.append("&");

            String key = entry.getKey();
            String value = entry.getValue();
            if (StrKit.notBlank(value))
                try {
                    value = URLEncoder.encode(value, CHARSET);
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            sb.append(key).append("=").append(value);
        }
        return sb.toString();
    }

    private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {
        URL _url = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
        conn.setRequestMethod(method);
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setConnectTimeout(19000);
        conn.setReadTimeout(19000);
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");
        if (headers != null && !headers.isEmpty())
            for (Map.Entry<String, String> entry : headers.entrySet())
                conn.setRequestProperty(entry.getKey(), entry.getValue());
        return conn;
    }

    private static String readResponseString(HttpURLConnection conn) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        try {
            inputStream = conn.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET));
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    LogKit.error(e.getMessage(), e);
                }
            }
        }
    }

    public static String sendMsg(String dataInfo) {
        com.alibaba.fastjson.JSONObject accessTokenJson = WxKit.getAccessToken(MainConfig.APP_ID, MainConfig.APP_SECRET);
        if (accessTokenJson != null) {
            HttpURLConnection conn = null;
            Map<String, String> map = new HashMap<>();
            map.put("access_token", accessTokenJson.get("access_token").toString());
            try {
                conn = getHttpConnection(buildUrlWithQueryString(sendmsg_url, map), "POST", null);
                conn.connect();
                OutputStream out = conn.getOutputStream();
                out.write(dataInfo.getBytes(CHARSET));
                out.flush();
                out.close();
                return readResponseString(conn);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }
        }

        return "";
    }


    /**
     * 给企业微信用户推送通知
     *
     * @param content
     * @param openIds
     */
    public static void sendMessage(String content, List<String> openIds) {
        if (openIds == null || openIds.size() == 0) {
            return;
        }
        System.out.println(openIds);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < openIds.size(); i++) {
            if (i == 0) {
                sb.append(openIds.get(i));
            } else {
                sb.append("|" + openIds.get(i));
            }
        }
        _log.debug("Sending wx message to {}", sb);
        PushMsgForm text = new PushMsgForm();
        text.setAgentid(MainConfig.APP_AGENTID);
        text.setText(Kv.by("content", content));
        text.setSafe(0);
        text.setTouser(sb.toString());
        text.setMsgtype("text");

//        System.out.println(String.valueOf(JsonKit.toJson(text)));
        try {
            String resultJsonStr = sendMsg(JsonKit.toJson(text));
            _log.debug("The result string of send weixin msg: {}", resultJsonStr);

            if (StrKit.notBlank(resultJsonStr)) {
                JSONObject result = JSONObject.parseObject(resultJsonStr);
                if (result != null && result.containsKey("errcode")) {
                    if (result.getInteger("errcode") > 0) {
                        _log.error("Error when send msg: {}", result.getString("errmsg"));
                    }
                }
            }
        } catch (Exception e) {
            _log.error("Exception when send msg", e);
        }
    }

}
